package com.bzkj.document.utils.otheroutbound;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.bzkj.common.domain.NccApiResponse;
import com.bzkj.document.enums.ProcessingType;
import com.bzkj.document.exception.WarehouseNotFoundException;
import com.bzkj.document.mapper.OtherOutboundMapper;
import com.bzkj.document.mapper.WmsWareHouseInventoryMapper;
import com.bzkj.document.utils.common.DataProcessUtils;
import com.bzkj.document.utils.common.InventoryManagerUtils;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

/**
 * @projectName: prt-wms
 * @package: com.bzkj.document.utils.otheroutbound
 * @className: OtherOutboundUtils
 * @description: 其他出库单处理工具类
 * @author: C1309
 * @createDate: 2025年01月06日
 * @version: v1.0
 */
@Component
public class OtherOutboundUtils {
    @Resource
    private OtherOutboundMapper otherOutboundMapper;

    @Resource
    private InventoryManagerUtils inventoryManagerUtils;

    @Resource
    private WmsWareHouseInventoryMapper wareHouseInventoryMapper;

    @Resource
    @Qualifier("threadPoolTaskExecutor")
    private ThreadPoolTaskExecutor executor;

    // ==========================================================
    // 模块名称: 其他出库单解析模块
    // 功能描述: 解析其他出库单相关的业务逻辑
    // ==========================================================

    /**
     * 解析NCC其他出库单
     *
     * @param nccApiResponse 接口返回数据
     * @param type           解析类型（0：查询，1：确认，2：修改）
     * @return 单据查询结果
     */
    public List<Map<String, Object>> parsingOtherOutboundOrders(NccApiResponse nccApiResponse, int type, Boolean isConfirm) {
        JSONArray dataArray = nccApiResponse.getData() == null ? new JSONArray() : nccApiResponse.getData();

        List<CompletableFuture<Map<String, Object>>> futures = dataArray.stream()
                .map(dataObject -> JSONObject.parseObject(JSONObject.toJSONString(dataObject))) // 显式转换为 JSONObject
                .map(dataObject -> CompletableFuture.supplyAsync(() -> processOrder(dataObject, type, isConfirm), executor))
                .collect(Collectors.toList());
        CompletableFuture<Void> allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));

        try {
            allFutures.get(); // 等待所有线程完成
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException("处理订单时发生异常", e);
        }

        return futures.stream()
                .map(CompletableFuture::join)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    private Map<String, Object> processOrder(JSONObject dataObject, int type, Boolean isConfirm) {
        // 解析订单头
        JSONObject generalOutHead = dataObject.getJSONObject("ic.GeneralOutHeadVO");
        if (generalOutHead == null) {
            return null; // 跳过缺少订单头的数据
        }
        Map<String, Object> generalOutHeadMap = parseGeneralOutHead(generalOutHead);
        String vbillcode = generalOutHeadMap.get("vbillcode").toString();
        Object cwarehouseid = generalOutHeadMap.get("cwarehouseid");
        String cgeneralhid = generalOutHead.get("cgeneralhid").toString();
        String vtrantypecode = generalOutHead.get("vtrantypecode") == null ? "" : generalOutHead.get("vtrantypecode").toString();

        // 判断其他出库单是否是创建转库单所创建的
        if ("4I-02".equals(generalOutHeadMap.get("vtrantypecode"))) {
            return null;
        }

        // 判断其他出库单是否已经被WMS确认
        int isExist = otherOutboundMapper.selectIsExist(vbillcode);
        if (isExist > 0 && isConfirm) {
            return null;
        } else {
            generalOutHeadMap.put("isConfirm", 0);
        }

        // 解析订单行
        JSONArray otherOutBodyList = dataObject.getJSONArray("ic.GeneralOutBodyVO");
        if (otherOutBodyList == null || otherOutBodyList.isEmpty()) {
            return null; // 跳过没有订单行的数据
        }
        List<Map<String, Object>> details = parseOtherOutBodyList(otherOutBodyList, vbillcode, cwarehouseid, type, cgeneralhid, vtrantypecode);

        // 包装订单头和订单行信息
        Map<String, Object> billData = new HashMap<>(2);
        billData.put("header", generalOutHeadMap);
        billData.put("details", details);

        return billData;
    }

    /**
     * 解析订单头数据
     *
     * @param generalOutHeadVO 订单头 JSON 对象
     * @return 订单头解析结果
     */
    private Map<String, Object> parseGeneralOutHead(JSONObject generalOutHeadVO) {
        // 解析订单头逻辑
        HashMap<String, Object> generalOutHeadMap = new HashMap<>(20);

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // trafficorgvid(物流组织）
        DataProcessUtils.processField(generalOutHeadVO, generalOutHeadMap, "trafficorgvid");

        // fbillflag(单据状态）
        DataProcessUtils.getStringField(generalOutHeadVO, "fbillflag", generalOutHeadMap);

        // cgeneralhid(表头主键）
        DataProcessUtils.getStringField(generalOutHeadVO, "cgeneralhid", generalOutHeadMap);

        // ctrantypeid(出入库类型）
        DataProcessUtils.getStringField(generalOutHeadVO, "ctrantypeid", generalOutHeadMap);

        // ntotalnum(总数量）
        DataProcessUtils.getFormattedDouble(generalOutHeadVO, "ntotalnum", generalOutHeadMap);

        // dmakedate（制单日期）
        DataProcessUtils.handleDateField(generalOutHeadVO, "dmakedate", sdf, generalOutHeadMap);

        // billmaker（制单人）
        DataProcessUtils.processField(generalOutHeadVO, generalOutHeadMap, "billmaker");

        // creationtime(创建时间)
        DataProcessUtils.handleDateField(generalOutHeadVO, "creationtime", sdf, generalOutHeadMap);

        // pk_org_v(库存组织）
        DataProcessUtils.processField(generalOutHeadVO, generalOutHeadMap, "pk_org_v");

        //dbilldate（单据日期）
        DataProcessUtils.handleDateField(generalOutHeadVO, "dbilldate", sdf, generalOutHeadMap);

        // creator(创建人）
        DataProcessUtils.processField(generalOutHeadVO, generalOutHeadMap, "creator");

        // cwarehouseid(仓库）
        DataProcessUtils.processField(generalOutHeadVO, generalOutHeadMap, "cwarehouseid");

        // vtrantypecode（出库类型编码）
        DataProcessUtils.getStringField(generalOutHeadVO, "vtrantypecode", generalOutHeadMap);

        // vbillcode（单据编号）
        DataProcessUtils.getStringField(generalOutHeadVO, "vbillcode", generalOutHeadMap);

        //corpoid(公司）
        DataProcessUtils.processField(generalOutHeadVO, generalOutHeadMap, "corpoid");

        //corpvid
        DataProcessUtils.processField(generalOutHeadVO, generalOutHeadMap, "corpvid");

        // cbizid(业务员）
        DataProcessUtils.processField(generalOutHeadVO, generalOutHeadMap, "cbizid");

        // cdptvid（部门）
        DataProcessUtils.processField(generalOutHeadVO, generalOutHeadMap, "cdptvid");

        //cdptid(部门）
        DataProcessUtils.processField(generalOutHeadVO, generalOutHeadMap, "cdptid");

        // vnote（备注）
        DataProcessUtils.getStringField(generalOutHeadVO, "vnote", generalOutHeadMap);

        // vdef3（需求日期）
        DataProcessUtils.handleDateField(generalOutHeadVO, "vdef3", sdf, generalOutHeadMap);

        // ntotalpiece（应出总件数）
        DataProcessUtils.getFormattedDouble(generalOutHeadVO, "ntotalpiece", generalOutHeadMap);

        return generalOutHeadMap;
    }

    /**
     * 解析订单行数据列表
     *
     * @param otherOutBodyList 订单行 JSON 数组
     * @param vbillcode        单据编号
     * @param cwarehouseid     仓库编号
     * @param type             解析类型（0：查询，1：确认，2：修改）
     * @param cgeneralhid      表头主键
     * @return 订单行解析结果列表
     */
    private List<Map<String, Object>> parseOtherOutBodyList(JSONArray otherOutBodyList, String vbillcode, Object cwarehouseid,
                                                            int type, String cgeneralhid, String vtrantypecode) {
        List<Map<String, Object>> details = new ArrayList<>();
        List<Exception> exceptions = new ArrayList<>();
        for (int j = 0; j < otherOutBodyList.size(); j++) {
            // 解析单据行
            JSONObject otherOutBody = otherOutBodyList.getJSONObject(j);
            // 调用解析方法
            Map<String, Object> bodyMap = parsingOtherOutBodyVOList(otherOutBody);

            if (type == ProcessingType.CONFIRM_ORDER.ordinal()) {
                try {
                    processWarehouseInfo(bodyMap, cwarehouseid);
                } catch (Exception e) {
                    exceptions.add(e);
                }
            }
            bodyMap.put("cwarehouseid", cwarehouseid);
            bodyMap.put("vbillcode", vbillcode);
            bodyMap.put("cgeneralhid", cgeneralhid);
            bodyMap.put("vtrantypecode", vtrantypecode);
            details.add(bodyMap);
        }
        // 流处理完成后，统一处理异常
        if (!exceptions.isEmpty()) {
            // 可以记录日志、抛出聚合异常，或进行其他处理
            StringBuilder errorMessage = new StringBuilder();
            for (Exception exception : exceptions) {
                if (errorMessage.toString().isEmpty()) {
                    errorMessage.append("<ul>");
                }
                errorMessage.append(exception.getMessage());
            }
            throw new RuntimeException(errorMessage.append("</ul>").toString());
        }
        return details;
    }

    /***
     * 处理仓库信息
     * @param bodyMap 订单行数据
     * @param cwarehouseid NCC仓库信息
     */
    private void processWarehouseInfo(Map<String, Object> bodyMap, Object cwarehouseid) {
        String pkOrCode = DataProcessUtils.getPkOrCode(bodyMap, "cmaterialoid");
        @SuppressWarnings("unchecked")
        Map<String, Object> cmaterialoid = (Map<String, Object>) bodyMap.get("cmaterialoid");
        Object crowno = bodyMap.get("crowno");
        String warehousePk = DataProcessUtils.getPkOrCode((Map<String, Object>) cwarehouseid);
        List<HashMap<String, String>> warehouseList = inventoryManagerUtils.selectNccWarehouse(pkOrCode, warehousePk);
        if (warehouseList != null && !warehouseList.isEmpty()) {
            HashMap<String, String> hashMap = warehouseList.get(0);
            bodyMap.put("sto_id", hashMap.get("sto_id"));
            bodyMap.put("stu_class_id", hashMap.get("stu_class_id"));
        } else {
            String errorMsg = "<li>行号->" + crowno + "：物料名称：<b>" + cmaterialoid.get("name") +
                    "<b>" + "在WMS系统中无法分配对应仓库！</li>";
            throw new WarehouseNotFoundException(errorMsg);
        }
    }

    /**
     * 解析ic.GeneralOutBodyVO
     *
     * @param jsonObject JSONObject实体类
     * @return 解析后的数据
     */
    private Map<String, Object> parsingOtherOutBodyVOList(JSONObject jsonObject) {
        HashMap<String, Object> generalOutBodyMap = new HashMap<>(16);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // dproducedate(生产日期)
        DataProcessUtils.handleDateField(jsonObject, "dproducedate", sdf, generalOutBodyMap);

        //cbodytranstypecode(出库类型编码）
        DataProcessUtils.getStringField(jsonObject, "cbodytranstypecode", generalOutBodyMap);

        //nshouldassistnum(应发数量）
        DataProcessUtils.getFormattedDouble(jsonObject, "nshouldassistnum", generalOutBodyMap);

        //cgeneralhid(表头主键）
        DataProcessUtils.getStringField(jsonObject, "cgeneralhid", generalOutBodyMap);

        // pk_batchcode(批次主键）
        DataProcessUtils.getStringField(jsonObject, "pk_batchcode", generalOutBodyMap);

        //cgeneralbid（表体主键）
        DataProcessUtils.getStringField(jsonObject, "cgeneralbid", generalOutBodyMap);

        //nshouldnum(应发主数量）
        DataProcessUtils.getFormattedDouble(jsonObject, "nshouldnum", generalOutBodyMap);

        //castunitid（单位）
        DataProcessUtils.processField(jsonObject, generalOutBodyMap, "castunitid");

        //cunitid（主单位）
        DataProcessUtils.processField(jsonObject, generalOutBodyMap, "cunitid");

        //bonroadflag(是否在途）
        DataProcessUtils.getStringField(jsonObject, "bonroadflag", generalOutBodyMap);

        // dvalidate（失效日期）
        DataProcessUtils.handleDateField(jsonObject, "dvalidate", sdf, generalOutBodyMap);

        //cbodywarehouseid（库存仓库）
        DataProcessUtils.processField(jsonObject, generalOutBodyMap, "cbodywarehouseid");

        //cmaterialvid(物料信息）
        DataProcessUtils.processField(jsonObject, generalOutBodyMap, "cmaterialvid");

        @SuppressWarnings("unchecked")
        HashMap<String, Object> pkMaterial = (HashMap<String, Object>) generalOutBodyMap.get("cmaterialvid");

        // 查询物料的其他信息（保质期管理、批次管理、保质期单位、保质期）
        String pk = pkMaterial.get("pk").toString();
        HashMap<String, Object> additionMap = wareHouseInventoryMapper.selectAdditionalManagement(pk);
        generalOutBodyMap.put("additionMap", additionMap);

        //pk_org_v（库存组织）
        DataProcessUtils.processField(jsonObject, generalOutBodyMap, "pk_org_v");

        //cproductorid（生产厂商）
        DataProcessUtils.processField(jsonObject, generalOutBodyMap, "cproductorid");

        //vchangerate（换算率）
        DataProcessUtils.getStringField(jsonObject, "vchangerate", generalOutBodyMap);

        //crowno（行号）
        DataProcessUtils.getStringField(jsonObject, "crowno", generalOutBodyMap);

        // vbatchcode（批次号）
        DataProcessUtils.getStringField(jsonObject, "vbatchcode", generalOutBodyMap);

        //pk_lotno_148
        DataProcessUtils.processField(jsonObject, generalOutBodyMap, "pk_lotno_148");

        //nnum（实发主数量）
        DataProcessUtils.getFormattedDouble(jsonObject, "nnum", generalOutBodyMap);

        //dbizdate（出库日期）
        DataProcessUtils.handleDateField(jsonObject, "dbizdate", sdf, generalOutBodyMap);

        //ts
        DataProcessUtils.handleDateField(jsonObject, "ts", sdf, generalOutBodyMap);

        //corpvid个（公司
        DataProcessUtils.processField(jsonObject, generalOutBodyMap, "corpvid");

        //nassistnum（实发数量）
        DataProcessUtils.getFormattedDouble(jsonObject, "nassistnum", generalOutBodyMap);

        //cmaterialoid（物料）
        DataProcessUtils.processField(jsonObject, generalOutBodyMap, "cmaterialoid");

        //corpoid
        DataProcessUtils.processField(jsonObject, generalOutBodyMap, "corpoid");

        //cstateid（库存状态）
        DataProcessUtils.getStringField(jsonObject, "cstateid", generalOutBodyMap);

        // 供应商批次号
        DataProcessUtils.getStringField(jsonObject, "vvendbatchcode", generalOutBodyMap);

        //cmaterialvid.vapprovalnumber_148（批准文号）
        String vapprovalnumber148 = jsonObject.getString("cmaterialvid.vapprovalnumber_148");
        generalOutBodyMap.put("vapprovalnumber_148", vapprovalnumber148 == null ? "" : vapprovalnumber148);

        // cmaterialvid.vmanufacturer_148（生产厂商）
        DataProcessUtils.processField(jsonObject, generalOutBodyMap, "cmaterialvid.vmanufacturer_148");
        if (generalOutBodyMap.get("cmaterialvid.vmanufacturer_148") != null) {
            Object vmanufacturer148 = generalOutBodyMap.get("cmaterialvid.vmanufacturer_148");
            generalOutBodyMap.remove("cmaterialvid.vmanufacturer_148");
            generalOutBodyMap.put("vmanufacturer_148", vmanufacturer148);
        }

        // cmaterialvid.cholder_148（持有人、注册人）
        DataProcessUtils.processField(jsonObject, generalOutBodyMap, "cmaterialvid.cholder_148");
        if (generalOutBodyMap.get("cmaterialvid.cholder_148") != null) {
            Object cholder148 = generalOutBodyMap.get("cmaterialvid.cholder_148");
            generalOutBodyMap.remove("cmaterialvid.cholder_148");
            generalOutBodyMap.put("cholder_148", cholder148);
        }

        // cvendorid（供应商）
        DataProcessUtils.processField(jsonObject, generalOutBodyMap, "cvendorid");

        //vbcdef1（合箱说明）
        DataProcessUtils.getStringField(jsonObject, "vbcdef1", generalOutBodyMap);

        // vbcdef2（供应商代码）
        DataProcessUtils.getStringField(jsonObject, "vbcdef2", generalOutBodyMap);

        // vbcdef3（包材版本）
        DataProcessUtils.getStringField(jsonObject, "vbcdef3", generalOutBodyMap);

        // vbdef48（复验期）
        DataProcessUtils.getStringField(jsonObject, "vbdef48", generalOutBodyMap);

        return generalOutBodyMap;
    }
}
